// ============================================================================
//
// Copyright (C) 2006-2007 Dengues
//
// Google Group: http://groups.google.com/group/dengues
// QQ Group: 24885404
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// ============================================================================
package org.dengues.core.resource;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.dengues.commons.utils.FileUtils;
import org.dengues.core.DenguesCorePlugin;
import org.dengues.core.ExceptionOperation;
import org.dengues.core.warehouse.ENodeCategoryName;
import org.dengues.core.warehouse.ENodeStatus;
import org.dengues.core.warehouse.IWarehouseNode;
import org.dengues.core.warehouse.IWarehouseObject;
import org.dengues.model.database.DatabaseDiagram;
import org.dengues.model.project.ProjectType;
import org.dengues.model.warehouse.BlockExitType;
import org.dengues.model.warehouse.ProcessType;
import org.dengues.model.warehouse.ScriptsStorage;
import org.dengues.model.warehouse.Storage;
import org.dengues.model.warehouse.WarehouseFactory;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.util.EcoreUtil;

/**
 * Qiang.Zhang.Adolf@gmail.com class global comment. Detailled comment <br/>
 * 
 * $Id: Dengues.epf 2007-12-5 qiang.zhang $
 * 
 */
public class WarehouseResourceFactory {

    private static ProcessType blockProcess;

    private static DenguesResourceManager manager = new DenguesResourceManager();

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "createStorage".
     * 
     * @param storage
     * @param path
     * @return
     */
    public static String createStorage(Storage storage, IPath path) {
        String pathName = "";
        ENodeCategoryName name = ENodeCategoryName.PROCESS;
        name = ENodeCategoryName.getENodeCategory(storage.getCategoryName());
        if (storage instanceof ScriptsStorage) {
            name = ENodeCategoryName.SCRIPTS;
        }
        Resource itemResource = manager.createStorageResource(storage, getProject(), path, name);
        itemResource.getContents().add(storage);
        manager.saveResource(itemResource);
        pathName = itemResource.getURI().toFileString();
        return pathName;
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "getProject".
     * 
     * @return
     */
    public static IProject getProject() {
        return DenguesProjectFactory.getDenguesProject().getProject();
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "getObjectNamesFromEMF".
     * 
     * @param name
     * @param path
     * @param names
     */
    private static void getObjectNamesFromEMF(ENodeCategoryName name, IPath path, List<String> names) {
        List<Object> list = new ArrayList<Object>();

        if (path.segmentCount() == 0) {
            list = getObjectFromEMF(name, path);
        } else {
            list = getObjectFromEMF(list, name, getProject().getFolder(path), false);
        }
        for (Object object : list) {
            if (object instanceof IFolder) {
                getObjectNamesFromEMF(name, ((IFolder) object).getProjectRelativePath(), names);
            }
            if (name == ENodeCategoryName.PROCESS && object instanceof ProcessType) {
                names.add(((ProcessType) object).getName());
            } else if (name == ENodeCategoryName.DATABASE && object instanceof DatabaseDiagram) {
                names.add(((DatabaseDiagram) object).getName());
            } else if (name == ENodeCategoryName.SCRIPTS && object instanceof ScriptsStorage) {
                names.add(((ScriptsStorage) object).getName());
            }
        }
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "getFolder".
     * 
     * @param name
     * @param relative
     * @return
     */
    public static IFolder getFolder(ENodeCategoryName name, IPath relative) {
        IFolder folder = getFolder(name);
        return folder.getFolder(relative);
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "getSubFolderNames".
     * 
     * @param name
     * @param parent
     * @return
     */
    public static List<String> getSubFolderNames(ENodeCategoryName name, IPath parent) {
        List<String> names = new ArrayList<String>();
        IFolder folder = getFolder(name);
        IFolder subFolder = folder.getFolder(parent);
        if (subFolder.exists()) {
            try {
                IResource[] members = folder.members();
                for (IResource resource : members) {
                    if (resource instanceof IFolder) {
                        IFolder file = (IFolder) resource;
                        names.add(file.getName());
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return names;
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "getObjectFromEMF".
     * 
     * @param name
     * @param path
     * @return
     */
    public static List<Object> getObjectFromEMF(ENodeCategoryName name, IPath path) {
        IFolder folder = getFolder(name);
        folder = folder.getFolder(path);
        List<Object> list = new ArrayList<Object>();
        return getObjectFromEMF(list, name, folder, false);
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "getFolder".
     * 
     * @param name
     * @return
     */
    public static IFolder getFolder(ENodeCategoryName name) {
        IFolder folder = manager.getFolder(getProject(), name, false);
        return folder;
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "getObjectFromEMF".
     * 
     * @param name
     * @param folder
     * @return
     */
    private static List<Object> getObjectFromEMF(List<Object> list, ENodeCategoryName name, IFolder folder, boolean all) {
        if (folder.exists()) {
            try {
                IResource[] members = folder.members();
                for (IResource resource : members) {
                    if (resource instanceof IFile) {
                        IFile file = (IFile) resource;
                        Storage loadDatabse = loadStorage(name, file);
                        list.add(loadDatabse);
                    } else if (resource instanceof IFolder) {
                        if (all) {
                            getObjectFromEMF(list, name, (IFolder) resource, all);
                        } else {
                            list.add(resource);
                        }
                    }
                }
            } catch (Exception e) {
                ExceptionOperation.operate(e);
            }
        }
        return list;
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "loadStorage".
     * 
     * @param name
     * @param file
     * @return
     */
    public static Storage loadStorage(ENodeCategoryName name, IFile file) {
        Storage loadDatabse = manager.loadStorage(file, name);
        return loadDatabse;
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "getFileFromEMF".
     * 
     * @param type
     * @param name
     * @param path
     * @param id
     * @return
     */
    public static IFile getFileFromEMF(String type, ENodeCategoryName name, IPath path, String id) {
        if (ENodeCategoryName.BLOCKS == name) {
            return getBlockFileFromEMF(type, id);
        }
        IFolder folder = manager.getFolder(getProject(), name, true);
        folder = folder.getFolder(path);
        try {
            IResource[] members = folder.members();
            for (IResource resource : members) {
                if (resource instanceof IFile) {
                    IFile file = (IFile) resource;
                    String simpleName = getSimpleName(name, file);
                    if (simpleName.equals(type) || simpleName.equals(id)) {
                        return file;
                    }
                }
            }
        } catch (Exception e) {
            ExceptionOperation.operate(e);
        }
        return null;
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "getSimpleName".
     * 
     * @param name
     * @param file
     * @return
     */
    public static String getSimpleName(ENodeCategoryName name, IFile file) {
        IPath fullPath = file.getFullPath();
        String removeFileExtension = fullPath.removeFileExtension().segment(fullPath.removeFileExtension().segmentCount() - 1);
        String version = DenguesResourceManager.SEPERATOR + name.getVersion();
        String simpleName = removeFileExtension.substring(0, removeFileExtension.indexOf(version));
        return simpleName;
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "save".
     * 
     * @param type
     */
    public static void saveStorage(Storage storage) {
        ENodeCategoryName name = ENodeCategoryName.PROCESS;
        name = ENodeCategoryName.getENodeCategory(storage.getCategoryName());
        if (storage instanceof ScriptsStorage) {
            name = ENodeCategoryName.SCRIPTS;
        }
        Resource typeResource = manager.getStorageResource(storage, name);
        typeResource.getContents().clear();
        typeResource.getContents().add(storage);
        manager.saveResource(typeResource);
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "save".
     * 
     * @param type
     */
    public static void save(ProjectType type) {
        Resource typeResource = manager.getTypeResource(type);
        typeResource.getContents().clear();
        typeResource.getContents().add(type);
        manager.saveResource(typeResource);
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "deleteObjectPhysical".
     * 
     * @param object
     */
    public static void deleteObjectPhysical(IWarehouseObject object) {
        Object data = object.getData();
        List<Resource> resources = new ArrayList<Resource>();
        if (data instanceof Storage) {
            Storage type = (Storage) data;
            resources = manager.getAffectedStorages(type);
        }
        for (Resource resource : resources) {
            manager.deleteResource(resource);
        }
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "deleteObjectDataPhysical".
     * 
     * @param data
     */
    public static void deleteObjectDataPhysical(Object data) {
        List<Resource> resources = new ArrayList<Resource>();
        if (data instanceof Storage) {
            Storage type = ((Storage) data);
            resources = manager.getAffectedStorages(type);
        }
        for (Resource resource : resources) {
            manager.deleteResource(resource);
        }
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "deleteObjectLogical".
     * 
     * @param object
     */
    public static void deleteObjectLogical(IWarehouseObject object) {
        Object data = object.getData();
        if (data instanceof Storage) {
            Storage type = ((Storage) data);
            type.setStatus(ENodeStatus.DELETED.getId());
            WarehouseResourceFactory.saveStorage(type);
        }
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "restoreObjectLogical".
     * 
     * @param object
     */
    public static void restoreObjectLogical(IWarehouseObject object) {
        Object data = object.getData();
        if (data instanceof Storage) {
            Storage type = ((Storage) data);
            type.setStatus(ENodeStatus.NORMAL.getId());
            WarehouseResourceFactory.saveStorage(type);
        }
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "moveObjectPhysical".
     * 
     * @param node
     * @param fullPath
     */
    public static void moveObjectPhysical(IWarehouseNode node, IPath fullPath) {
        IFolder folder = manager.getFolder(getProject(), node.getCategoryName(), false);
        IFile file = manager.getWarehouseFile(node);
        if (file.exists()) {
            IPath fullPath2 = file.getFullPath();
            IPath append = folder.getFile(fullPath).getProjectRelativePath().append(
                    fullPath2.segment(fullPath2.segmentCount() - 1));
            if (folder.getFile(append).exists()) {
                return;
            }
            String string = file.getProjectRelativePath().toString();
            String absolutePath = FileUtils.getRelativePath(append.toString(), string);
            try {
                file.move(new Path(absolutePath), false, null);
            } catch (CoreException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "getAllObjectNamesFromEMF".
     * 
     * @param process
     * @return
     */
    public static List<String> getAllObjectNamesFromEMF(ENodeCategoryName process) {
        List<String> names = new ArrayList<String>();
        Path path = new Path(""); //$NON-NLS-1$
        getObjectNamesFromEMF(process, path, names);
        return names;
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "getBlockFileFromEMF".
     * 
     * @param type2
     * 
     * @return
     */
    private static IFile getBlockFileFromEMF(String blockId, String type2) {
        IFolder folder = manager.getFolder(getProject(), ENodeCategoryName.BLOCKS, false);
        List<Object> list = new ArrayList<Object>();
        List<Object> objectFromEMF = getObjectFromEMF(list, ENodeCategoryName.PROCESS, folder, false);
        ProcessType type = null;
        for (Object object : objectFromEMF) {
            if (object instanceof ProcessType) {
                if (blockId.equals(((ProcessType) object).getUuid())) {
                    type = (ProcessType) object;
                }
            }
        }
        if (type == null) {
            type = WarehouseFactory.eINSTANCE.createProcessType();
            type.setUuid(blockId);
            type.setIsblock(true);
            type.setName(type2);
            type.setCategoryName(ENodeCategoryName.BLOCKS.getName());
            type.setCreation(new Date());
            type.setComment(type2);
            BlockExitType cbet = WarehouseFactory.eINSTANCE.createBlockExitType();
            cbet.setEnter(true);
            cbet.setName("Start");
            cbet.setSizeH(DenguesCorePlugin.getDefault().getDenguesUiService().getDefaultRectangle().height);
            cbet.setSizeW(DenguesCorePlugin.getDefault().getDenguesUiService().getDefaultRectangle().width);
            cbet.setPosX(DenguesCorePlugin.getDefault().getDenguesUiService().getDefaultRectangle().x);
            cbet.setPosY(DenguesCorePlugin.getDefault().getDenguesUiService().getDefaultRectangle().y);
            type.getExits().add(cbet);

            createStorage(type, new Path("")); //$NON-NLS-1$
        }
        blockProcess = type;
        StringBuffer fileName = manager.getFileName(ENodeCategoryName.BLOCKS, blockId);
        String file = new Path(fileName.toString()).addFileExtension(ENodeCategoryName.PROCESS.getExtension()).toOSString();
        return folder.getFile(file);

    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "getEMFId".
     * 
     * @return
     */
    public static String getEMFId() {
        return EcoreUtil.generateUUID();
    }

    /**
     * Getter for blockProcess.
     * 
     * @return the blockProcess
     */
    public static ProcessType getBlockProcess() {
        return blockProcess;
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "getObjectFromEMF".
     * 
     * @param name
     * @return
     */
    public static List<Object> getAllObjectsFromEMF(ENodeCategoryName name) {
        List<Object> names = new ArrayList<Object>();
        IFolder folder = getFolder(name);
        Path path = new Path(""); //$NON-NLS-1$
        folder = folder.getFolder(path);
        List<Object> list = new ArrayList<Object>();
        list = getObjectFromEMF(names, name, folder, true);
        return list;
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "copyObjectPhysical".
     * 
     * @param node
     * @param fullPath
     */
    public static void copyObjectPhysical(IWarehouseNode node, IPath fullPath) {
        IFolder folder = manager.getFolder(getProject(), node.getCategoryName(), false);
        IFile file = manager.getWarehouseFile(node);
        if (file.exists()) {
            IPath fullPath2 = file.getFullPath();
            IPath append = folder.getFile(fullPath).getProjectRelativePath().append(
                    fullPath2.segment(fullPath2.segmentCount() - 1));
            if (folder.getFile(append).exists()) {
                return;
            }
            String string = file.getProjectRelativePath().toString();
            String absolutePath = FileUtils.getRelativePath(append.toString(), string);
            try {
                file.copy(new Path(absolutePath), false, null);
            } catch (CoreException e) {
                e.printStackTrace();
            }
        }
    }
}
